package org.example.system.config;

import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.example.system.security.constant.SecurityConstants;
import org.springdoc.core.customizers.GlobalOpenApiCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpHeaders;

/**
 * Swagger 配置类
 * 负责配置 OpenAPI 文档和全局自定义扩展
 * 包括接口信息、安全认证配置等
 *
 * @author LY
 */
@Configuration
@Slf4j
@RequiredArgsConstructor
public class SwaggerConfig {

    private final Environment environment;

    /**
     * 配置 OpenAPI 文档基本信息
     * 包括文档标题、版本号和安全认证配置
     * 使用环境变量中的项目版本号，默认值为 1.0.0
     *
     * @return {@link OpenAPI} OpenAPI 配置对象
     */
    @Bean
    public OpenAPI openApi() {
        // 从配置文件中获取应用版本号，默认为 1.0.0
        String appVersion = environment.getProperty("project.version", "1.0.0");

        return new OpenAPI()
                .info(new Info()
                        .title("系统接口文档")
                        .version(appVersion)
                )
                // 配置全局安全认证参数
                .components(new Components()
                        .addSecuritySchemes(HttpHeaders.AUTHORIZATION,
                                new SecurityScheme()
                                        .name(HttpHeaders.AUTHORIZATION)  // 认证头名称
                                        .type(SecurityScheme.Type.APIKEY) // 认证类型
                                        .in(SecurityScheme.In.HEADER)     // 认证位置
                                        .scheme("Bearer")                 // 认证方案
                                        .bearerFormat("JWT")              // 认证格式
                        )
                );
    }

    /**
     * 全局自定义扩展配置
     * 为所有接口添加安全认证要求，排除登录和验证码接口
     * 在 OpenAPI 规范中，Operation 表示 API 端点或操作
     * 每个路径对象可以包含多个 Operation 对象，对应不同的 HTTP 方法
     * 该方法会遍历所有路径，为每个接口添加安全认证要求
     *
     * @return {@link GlobalOpenApiCustomizer} 全局自定义扩展对象
     */
    @Bean
    public GlobalOpenApiCustomizer globalOpenApiCustomizer() {
        return openApi -> {
            if (openApi.getPaths() == null) {
                return;
            }

            openApi.getPaths().forEach((path, pathItem) -> {
                // 排除指定路径
                if (shouldSkipSecurity(path)) {
                    return;
                }

                java.util.List<Operation> operations = pathItem.readOperations();
                if (operations != null) {
                    operations.forEach(operation -> operation.addSecurityItem(new SecurityRequirement().addList(HttpHeaders.AUTHORIZATION)));
                }
            });
        };
    }

    /**
     * 判断给定路径是否应跳过安全认证要求
     *
     * @param path 路径字符串
     * @return 是否跳过
     */
    private boolean shouldSkipSecurity(String path) {
        return SecurityConstants.LOGIN_PATH.equals(path) || SecurityConstants.CAPTCHA_PATH.equals(path);
    }
}